package com.weike.yuanding.strategy.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.weike.yuanding.constant.VideoStatusEnum;
import com.weike.yuanding.entity.VideoMainEntity;
import com.weike.yuanding.mapper.VideoMainMapper;
import com.weike.yuanding.service.VideoService;
import com.weike.yuanding.strategy.VideoStrategy;
import com.weike.yuanding.utils.BaseContext;
import com.weike.yuanding.vo.VideoResVo;
import com.weike.yuanding.vo.VideoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 推荐视频策略
 */
@Component("0")
public class RecommendVideoStrategy implements VideoStrategy {

    @Autowired
    private VideoMainMapper videoMainMapper;

    @Autowired
    private VideoService videoService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 推荐算法
     * @param videoVo 输入参数
     * @return 推荐的视频列表
     */
    @Override
    public List<VideoResVo> getVideoList(VideoVo videoVo) {
        // 获取当前用户ID
        String userId = BaseContext.userId.get();
        Set<String> currentUserViewed = new HashSet<>();
        if (userId != null) {
            // 从 Redis 获取当前用户的观看历史
            String viewedKey = "user:video:viewed:" + userId;
            Set<Object> currentUserViewedObj = redisTemplate.opsForSet().members(viewedKey);
            if (currentUserViewedObj != null) {
                currentUserViewed = currentUserViewedObj.stream().map(Object::toString).collect(Collectors.toSet());
            }
        }

        // 如果用户没有观看记录，则返回热门视频（查询时已排除空集合，不影响查询）
        if (userId == null || currentUserViewed.isEmpty()) {
            return getPopularVideos(currentUserViewed);
        }

        // 获取所有有观看记录的用户ID
        Set<Object> allUserIdsObj = redisTemplate.opsForSet().members("users:with:views");
        if (allUserIdsObj == null || allUserIdsObj.isEmpty()) {
            return getPopularVideos(currentUserViewed);
        }
        Set<String> allUserIds = allUserIdsObj.stream().map(Object::toString).collect(Collectors.toSet());

        // 获取其他用户的观看历史（用于计算相似度）和喜爱视频（用于推荐）
        Map<String, Set<String>> userViewedVideos = new HashMap<>();
        Map<String, Set<String>> userLikedVideos = new HashMap<>();
        for (String otherUserId : allUserIds) {
            if (!otherUserId.equals(userId)) {
                // 获取观看历史
                String otherViewedKey = "user:video:viewed:" + otherUserId;
                Set<Object> viewedObj = redisTemplate.opsForSet().members(otherViewedKey);
                if (viewedObj != null && !viewedObj.isEmpty()) {
                    Set<String> viewed = viewedObj.stream().map(Object::toString).collect(Collectors.toSet());
                    userViewedVideos.put(otherUserId, viewed);
                }
                // 获取喜爱视频
                String otherLikedKey = "user:video:liked:" + otherUserId;
                Set<Object> likedObj = redisTemplate.opsForSet().members(otherLikedKey);
                if (likedObj != null && !likedObj.isEmpty()) {
                    Set<String> liked = likedObj.stream().map(Object::toString).collect(Collectors.toSet());
                    userLikedVideos.put(otherUserId, liked);
                }
            }
        }

        // 找到相似用户（基于观看历史）
        List<String> similarUsers = new ArrayList<>();
        for (Map.Entry<String, Set<String>> entry : userViewedVideos.entrySet()) {
            double similarity = calculateSimilarity(currentUserViewed, entry.getValue());
            if (similarity > 0.5) { // 相似性阈值
                similarUsers.add(entry.getKey());
            }
        }

        // 若没有相似用户，则返回热门视频（已在查询时排除已观看视频）
        if (similarUsers.isEmpty()) {
            return getPopularVideos(currentUserViewed);
        }

        // 统计相似用户喜爱的视频频率，并排除当前用户已观看的视频
        Map<String, Integer> videoFrequency = new HashMap<>();
        for (String similarUser : similarUsers) {
            Set<String> likedVideos = userLikedVideos.getOrDefault(similarUser, Collections.emptySet());
            for (String video : likedVideos) {
                if (!currentUserViewed.contains(video)) {
                    videoFrequency.put(video, videoFrequency.getOrDefault(video, 0) + 1);
                }
            }
        }

        // 按频率排序获取基于相似度的推荐
        List<String> similarityBasedRecommendations = new ArrayList<>(videoFrequency.keySet());
        similarityBasedRecommendations.sort((a, b) -> videoFrequency.get(b) - videoFrequency.get(a));

        // 设定推荐数量
        int totalRecommendations = 5;
        List<String> finalRecommendations = new ArrayList<>();
        for (String videoId : similarityBasedRecommendations) {
            if (finalRecommendations.size() >= totalRecommendations) {
                break;
            }
            // 理论上已排除，但再次确认
            if (!currentUserViewed.contains(videoId)) {
                finalRecommendations.add(videoId);
            }
        }

        // 如果基于相似度的推荐不足5条，添加随机推荐，并排除已观看的视频
        if (finalRecommendations.size() < totalRecommendations) {
            int remainingCount = totalRecommendations - finalRecommendations.size();
            List<String> randomRecommendations = getRandomRecommendations(currentUserViewed, remainingCount);
            finalRecommendations.addAll(randomRecommendations);
        }

        return videoService.list(finalRecommendations);
    }

    /**
     * 获取随机推荐视频，直接在查询时排除用户已观看的视频
     * @param currentUserViewed 用户已观看的视频集合
     * @param count 需要获取的随机推荐数量
     * @return 随机推荐视频ID列表
     */
    private List<String> getRandomRecommendations(Set<String> currentUserViewed, int count) {
        // 查询时直接排除已观看的视频
        LambdaQueryWrapper<VideoMainEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VideoMainEntity::getStatus, VideoStatusEnum.YI_SHEN_HE.getCode());
        if (!currentUserViewed.isEmpty()) {
            queryWrapper.notIn(VideoMainEntity::getVideoId, currentUserViewed);
        }
        // 不做排序，查询所有符合条件的视频
        List<VideoMainEntity> availableVideos = videoMainMapper.selectList(queryWrapper);
        List<String> availableVideoIds = availableVideos.stream()
                .map(VideoMainEntity::getVideoId)
                .collect(Collectors.toList());
        Collections.shuffle(availableVideoIds);
        return availableVideoIds.stream().limit(count).collect(Collectors.toList());
    }

    /**
     * 计算两个视频集合的余弦相似性
     * @param set1 当前用户的视频集合
     * @param set2 其他用户的视频集合
     * @return 相似性得分
     */
    private double calculateSimilarity(Set<String> set1, Set<String> set2) {
        Set<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        int common = intersection.size();
        double magnitude1 = Math.sqrt(set1.size());
        double magnitude2 = Math.sqrt(set2.size());
        if (magnitude1 == 0 || magnitude2 == 0) {
            return 0.0;
        }
        return common / (magnitude1 * magnitude2);
    }

    /**
     * 获取热门视频作为默认推荐，直接在数据库查询时排除已观看的视频
     * @param currentUserViewed 当前用户已观看视频集合（可能为空）
     * @return 热门视频列表
     */
    private List<VideoResVo> getPopularVideos(Set<String> currentUserViewed) {
        LambdaQueryWrapper<VideoMainEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VideoMainEntity::getStatus, VideoStatusEnum.YI_SHEN_HE.getCode());
        if (!currentUserViewed.isEmpty()) {
            // 直接在查询时排除已观看的视频
            queryWrapper.notIn(VideoMainEntity::getVideoId, currentUserViewed);
        }
        queryWrapper.orderByDesc(VideoMainEntity::getPalyNumber);
        queryWrapper.last("LIMIT 5");

        List<VideoMainEntity> popularVideos = videoMainMapper.selectList(queryWrapper);
        List<String> ids = popularVideos.stream()
                .map(VideoMainEntity::getVideoId)
                .collect(Collectors.toList());
        if (ids.isEmpty()) {
            return new ArrayList<>();
        }
        return videoService.list(ids);
    }
}
